package com.ym.medical.service.impl;


import cn.binarywang.wx.miniapp.api.impl.WxMaServiceImpl;
import cn.hutool.core.exceptions.ExceptionUtil;
import com.alibaba.fastjson.JSONObject;
import com.ym.common.utils.CalcUtil;
import com.ym.common.utils.HttpUtil;
import com.ym.core.config.ConfigCenterProperties;
import com.ym.core.exception.BusinessException;
import com.ym.medical.domain.bo.pay.OrderModel;
import com.ym.medical.domain.bo.pay.WxApplyPaySign;
import com.ym.medical.domain.bo.pay.WxOrderQueryRespData;
import com.ym.medical.domain.bo.pay.WxRefundQueryRespData;
import com.ym.medical.enums.PlaformSourceEnum;
import com.ym.medical.enums.WxTradeTypeEnum;
import com.ym.medical.service.ISysSignSV;
import com.ym.medical.service.IWxPaySV;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.mp.api.WxMpService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;

/**
 * 微信支付相关
 */
@Service
@Transactional(rollbackFor = Exception.class)
@Slf4j
public class WxPaySVImpl implements IWxPaySV {

    @Autowired
    private ConfigCenterProperties configCenterProperties;

    @Autowired
    private ISysSignSV sysSignSV;

    @Autowired
    @Lazy
    private WxMaServiceImpl wxMaService;

    @Autowired
    @Lazy
    private WxMpService wxMpService;


    /**
     * 微信支付请求申请
     *
     * @param openId      用户的openid
     * @param outTradeNo  订单号
     * @param tradeType   交易类型 (必填项 JSAPI--JSAPI支付（或小程序支付）、NATIVE--Native支付、APP--app支付，MWEB--H5支付)
     * @param body        商品描述
     * @param callbackUrl 返回的url
     * @return
     */
    @Override
    public WxApplyPaySign.SignData payApply(String openId, String outTradeNo, WxTradeTypeEnum tradeType, String body, BigDecimal totalMoney, String callbackUrl) {
        log.info("微信支付-业务系统回调地址:{}", callbackUrl);
        String payUrl = configCenterProperties.getPayPlatform().getPayManaIp() + "/appPay";
        log.info("微信支付-支付系统请求签名地址:{}", payUrl);
        try {
            OrderModel orderModel = new OrderModel();
            orderModel.setAppId(getAppId(tradeType));
            orderModel.setBody(body);
            orderModel.setOpenId(openId);
            orderModel.setOutTradeNo(outTradeNo);
            orderModel.setTotalFee(String.valueOf(CalcUtil.init(totalMoney).mul(100).intValue()));
            orderModel.setTradeType(tradeType.getKey());
            orderModel.setCallbackUrl(callbackUrl);
            String reqBody = JSONObject.toJSONString(orderModel);
            log.info("微信支付-支付系统发起支付申请参数:{}", reqBody);
            //发起交易
            String execute = HttpUtil.post(payUrl).headers(sysSignSV.getTdSignHeaders(reqBody)).trustAllCerts().trustAllHosts().body(reqBody).execute();
            log.info("微信支付-支付系统发起支付申请响应:{}", execute);
            if (execute.contains("package")) {
                execute = execute.replaceAll("package", "packageStr");
            }
            WxApplyPaySign wxApplyPaySign = JSONObject.parseObject(execute, WxApplyPaySign.class);
            //6. 保存支付申请回话id
            if ("1".equals(wxApplyPaySign.getCode())) {
                WxApplyPaySign.ResponseData data = wxApplyPaySign.getData();
                if ("0000".equals(data.getRespCode())) {
                    return data.getRespData();
                } else {
                    throw new BusinessException("支付系统自定义respCode返回支付失败!");
                }
            } else {
                throw new BusinessException("支付系统异常!");
            }
        } catch (Exception e) {
            log.error(ExceptionUtil.stacktraceToString(e));
            throw new BusinessException("微信支付失败!");
        }
    }

    @Override
    public JSONObject refundApply(String outTradeNo, WxTradeTypeEnum tradeType, String outRefundNo, BigDecimal totalMoney, String callbackUrl) {
        log.info("微信退费-业务系统回调地址:{}", callbackUrl);
        String payUrl = configCenterProperties.getPayPlatform().getPayManaIp() + "/refund";
        log.info("微信退费-支付系统请求签名地址:{}", payUrl);
        try {
            OrderModel orderModel = new OrderModel();
            orderModel.setAppId(getAppId(tradeType));
            orderModel.setOutTradeNo(outTradeNo);
            orderModel.setTotalFee(String.valueOf(CalcUtil.init(totalMoney).mul(100).intValue()));
            orderModel.setTradeType(tradeType.getKey());
            orderModel.setCallbackUrl(callbackUrl);
            String reqBody = JSONObject.toJSONString(orderModel);
            log.info("微信退费申请参数:{}", reqBody);
            //发起交易
            String execute = HttpUtil.post(payUrl).headers(sysSignSV.getTdSignHeaders(reqBody)).trustAllCerts().trustAllHosts().body(reqBody).execute();
            log.info("微信退费申请响应:{}", execute);
            return JSONObject.parseObject(execute);
        } catch (Exception e) {
            log.error(ExceptionUtil.stacktraceToString(e));
            throw new BusinessException("微信退费失败!");
        }
    }

    @Override
    public void withdrawApply(String openId, String outTradeNo, WxTradeTypeEnum tradeType, BigDecimal totalMoney) {
        String payUrl = configCenterProperties.getPayPlatform().getPayManaIp() + "/transfersToChange";
        log.info("微信提现-支付系统请求签名地址:{}", payUrl);
        try {

            JSONObject reqBody = new JSONObject();
            reqBody.put("mch_appid", getAppId(tradeType));
            reqBody.put("partner_trade_no", outTradeNo);
            reqBody.put("amount", String.valueOf(CalcUtil.init(totalMoney).mul(100).intValue()));
            reqBody.put("openid", openId);

            log.info("微信提现申请参数:{}", reqBody.toJSONString());
            //发起交易
            String execute = HttpUtil.post(payUrl).headers(sysSignSV.getTdSignHeaders(reqBody.toJSONString())).trustAllCerts().trustAllHosts().body(reqBody.toJSONString()).execute();
            log.info("微信提现申请响应:{}", execute);
        } catch (Exception e) {
            log.error(ExceptionUtil.stacktraceToString(e));
            throw new BusinessException("微信提现失败!");
        }
    }

    /**
     * 微信交易订单查询
     *
     * @param plaformSourceEnum
     * @param outTradeNo        订单号
     * @return
     */
    @Override
    public WxOrderQueryRespData payOrderQuery(PlaformSourceEnum plaformSourceEnum, String outTradeNo) {
        WxOrderQueryRespData wxOrderQueryRespData;
        String payUrl = configCenterProperties.getPayPlatform().getPayManaIp() + "/orderQuery";
        log.info("微信交易订单查询-支付系统请求签名地址:{}", payUrl);
        try {

            JSONObject reqBody = new JSONObject();
            reqBody.put("appId", getAppIdByPaySource(plaformSourceEnum));
            reqBody.put("outTradeNo", outTradeNo);

            log.info("微信交易订单查询申请参数:{}", reqBody.toJSONString());
            //发起交易
            String execute = HttpUtil.post(payUrl).headers(sysSignSV.getTdSignHeaders(reqBody.toJSONString())).trustAllCerts().trustAllHosts().body(reqBody.toJSONString()).execute();
            log.info("微信提现申请响应:{}", execute);
            wxOrderQueryRespData = JSONObject.parseObject(execute, WxOrderQueryRespData.class);
            if (wxOrderQueryRespData == null
                    && !"SUCCESS".equals(wxOrderQueryRespData.getReturnCode())
                    && !"SUCCESS".equals(wxOrderQueryRespData.getResultCode())) {
                log.info("订单交易中");
                return null;
            }
        } catch (Exception e) {
            log.error(ExceptionUtil.stacktraceToString(e));
            throw new BusinessException("微信交易订单查询失败!");
        }
        return wxOrderQueryRespData;
    }

    /**
     * 微信退费订单查询
     *
     * @param plaformSourceEnum
     * @param outTradeNo        订单号
     * @return
     */
    @Override
    public WxRefundQueryRespData refundOrderQuery(PlaformSourceEnum plaformSourceEnum, String outTradeNo) {
        WxRefundQueryRespData wxRefundQueryRespData;
        String payUrl = configCenterProperties.getPayPlatform().getPayManaIp() + "/refundQuery";
        log.info("微信交易订单查询-支付系统请求签名地址:{}", payUrl);
        try {

            JSONObject reqBody = new JSONObject();
            reqBody.put("appId", getAppIdByPaySource(plaformSourceEnum));
            reqBody.put("outTradeNo", outTradeNo);

            log.info("微信交易订单查询申请参数:{}", reqBody.toJSONString());
            //发起交易
            String execute = HttpUtil.post(payUrl).headers(sysSignSV.getTdSignHeaders(reqBody.toJSONString())).trustAllCerts().trustAllHosts().body(reqBody.toJSONString()).execute();
            wxRefundQueryRespData = JSONObject.parseObject(execute, WxRefundQueryRespData.class);
            log.info("微信提现申请响应:{}", execute);
            if (wxRefundQueryRespData == null
                    && !"SUCCESS".equals(wxRefundQueryRespData.getReturnCode())
                    && !"SUCCESS".equals(wxRefundQueryRespData.getResultCode())) {
                log.info("订单交易中");
                return null;
            }
        } catch (Exception e) {
            log.error(ExceptionUtil.stacktraceToString(e));
            throw new BusinessException("微信交易订单查询失败!");
        }
        return wxRefundQueryRespData;
    }

    /**
     * 获取wxAppId
     *
     * @return
     */
    private String getAppId(WxTradeTypeEnum tradeType) {
        String appid = wxMaService.getWxMaConfig().getAppid();
        if ("MWEB".equals(tradeType)) {
            appid = wxMpService.getWxMpConfigStorage().getAppId();
        }
        return appid;
    }

    /**
     * 根据支付来源获取appid
     *
     * @param plaformSourceEnum
     * @return
     */
    private String getAppIdByPaySource(PlaformSourceEnum plaformSourceEnum) {
        String appid = null;
        if (PlaformSourceEnum.SMALL_PROGRAM.getKey().equals(plaformSourceEnum.getKey())) {
            appid = wxMaService.getWxMaConfig().getAppid();
        } else if (PlaformSourceEnum.THE_PUBLIC.getKey().equals(plaformSourceEnum.getKey())) {
            appid = wxMpService.getWxMpConfigStorage().getAppId();
        }
        return appid;
    }


}
